#!/usr/bin/env ruby
# frozen_string_literal: true

require 'optparse'
require 'fileutils'
require 'json'
require 'pry'

module ConfigItems
  class << self
    def read_config_items
      config_dir = File.expand_path(File.join(__dir__, '../../data/gits'))
      config_path = File.join(config_dir, 'config_user.json')
      if File.exist?(config_path)
        JSON.parse(File.read(config_path))
      else
        []
      end
    end

    def write_config_items(config_items)
      config_dir = File.expand_path(File.join(__dir__, '../../data/gits'))
      config_path = File.join(config_dir, 'config_user.json')
      FileUtils.mkdir_p(config_dir) unless File.exist?(config_dir)
      File.write(config_path,
                 JSON.pretty_generate(config_items, indent: '  ', space: ' '))

      puts "写入到 #{config_path}"
    end
  end
end

module UserReaders
  module Interactively
    class << self
      def read_user(action)
        action == 'store' ? interactively_input : interactively_select
      end

      private

        def interactively_input
          print '输入姓名：'
          name = gets

          print '输入邮箱：'
          email = gets

          { 'name' => name.strip, 'email' => email.strip }
        end

        # 交互式地选择姓名和邮箱
        def interactively_select
          # 读取所有配置
          config_items = ConfigItems.read_config_items
          config_items.each_with_index do |item, index|
            puts "#{index + 1} - #{item['id']}: #{item['name']} <#{item['email']}>"
          end

          print '输入序号或名字：'
          id = gets.strip

          item = config_items.find { |it| it['id'] == id }
          item = config_items[id.to_i - 1] if item.nil? && id =~ /^\d+$/ && id.to_i > 0
          unless item
            puts '序号或名称不正确！'
            exit 1
          end

          item
        end
    end
  end

  class FromCommits
    class << self
      def read_user(action = nil)
        authors = list_users_from_commits

        authors.each_with_index do |author, index|
          puts "#{index + 1}: #{author['name']} <#{author['email']}>"
        end

        print '输入序号或名字：'
        input = gets.strip

        if input =~ /^\d/
          author = authors[input.to_i - 1]
        else
          author = authors.find { |a| a['name'] == input }
        end
        if author
          author
        else
          puts '序号或名称不正确！'
          exit 1
        end
      end

      private

        def list_users_from_commits
          output = `git shortlog --summary --email`
          output.split("\n").map do |line|
            _, _, name, email = line.split(/\s+/)
            { 'name' => name, 'email' => email[1..-2] }
          end.reverse
        end
    end
  end

  class FromLastCommit
    class << self
      def read_user
        name = `git log -1 --pretty=format:"%an"`
        email = `git log -1 --pretty=format:"%ae"`

        puts "从最近一次提交中获取到用户配置：#{name} <#{email}>"
        { 'name' => name.strip, 'email' => email.strip }
      end
    end
  end
end

module Actions
  class << self
    def store(new_item)
      print '为本次保存取个 id（同名 id 将覆盖）：'
      id = gets.strip
      if id.empty?
        warn '未设置 id，将退出'
        exit 1
      end

      # 读取配置
      config_items = ConfigItems.read_config_items

      # 将 item 的数据写入到 config_items
      item = config_items.find { |it| it['id'] == id }
      if item
        item.merge!(new_item)
      else
        item = { 'id' => id, **new_item }
        config_items << item
      end

      # 写入配置
      ConfigItems.write_config_items(config_items)
      puts "已添加：#{item['name']} <#{item['email']}>"
    end

    def config(item)
      system "git config user.name #{item['name']}"
      system "git config user.email #{item['email']}"
      puts "已配置用户为 #{item['name']} <#{item['email']}>"
    end

    def print_item(item)
      puts "您的选择是：#{item['name']} <#{item['email']}>"
    end

  end
end

def read_user(origin, action)
  case origin
  when '-interactive'
    UserReaders::Interactively.read_user(action)
  when '-commits'
    UserReaders::FromCommits.read_user(action)
  when '-last-commit'
    UserReaders::FromLastCommit.read_user(action)
  else
    raise "Unknown origin: #{origin}"
  end
end

invoke_methods = []
origins = []

ARGV << '-h' if ARGV.empty?

OptionParser.new do |opts|
  opts.banner = <<~BANNER
    交互式地配置姓名和邮箱
  BANNER

  opts.on(nil, '--store', '指定动作：保存姓名和邮箱') do
    invoke_methods << 'store'
  end

  opts.on(nil, '--config', '指定动作：配置姓名和邮箱') do
    invoke_methods << 'config'
  end

  opts.on(nil, '--print', '指定动作：打印姓名和邮箱') do
    invoke_methods << 'print_item'
  end

  opts.on(nil, '--interactive', '交互式地输入姓名和邮箱') do
    origins << '-interactive'
  end

  opts.on(nil, '--from-last-commit', '从最近的提交中提取姓名和邮箱') do
    origins << '-last-commit'
  end

  opts.on(nil, '--from-commits', '从最近的提交中选择姓名和邮箱') do
    origins << '-commits'
  end
end.parse!

origins = ['-interactive'] if origins.empty?
if origins.length > 1
  STDERR.puts "错误：指定了多个源获取姓名和邮箱"
  exit 1
end

origin = origins[0]
if invoke_methods.empty?
  warn '未指定动作，将打印姓名和邮箱。'
  invoke_methods = ['print_item']
end

invoke_methods.each do |action|
  item = read_user(origin, action)
  Actions.send action, item
end
